import { ILayerItem } from "@/system/Common/interfaces";
import * as Cesium from "cesium";
import { LayerIdFlag } from "./LayerConfig";


export default class LayerManager {

    private static instance: LayerManager;
    private viewer: Cesium.Viewer
    private layersIdMap = new Map<string, ILayerItem & { handle?: any }>()

    constructor(viewer: Cesium.Viewer) {
        this.viewer = viewer
    }

    // 获取单例实例
    public static getInstance(viewer?: Cesium.Viewer): LayerManager {
        if (!LayerManager.instance) {
            if (!viewer) throw new Error("LayerManager需要传入viewer实例");
            LayerManager.instance = new LayerManager(viewer);
        }
        return LayerManager.instance;
    }

    /* 添加图层 */
    async Add(item: ILayerItem): Promise<void> {
        if (this.layersIdMap.has(item.id)) {
            return
        }
        const { type, show = true, alpha = 1, zIndex = 0 } = item
        let handle: any
        let provider: Cesium.ImageryProvider
        switch (type) {
            /* ---- 影像 ---- */
            case 'imagery_wmts':
                provider = new Cesium.WebMapTileServiceImageryProvider({
                    url: item.url!,
                    layer: item.layer!,
                    style: item.style || '',
                    format: item.format || 'image/png',
                    tileMatrixSetID: item.tileMatrixSetID || "EPSG:4326",
                    tileMatrixLabels: item.tileMatrixLabels || undefined,
                    tilingScheme: item.tilingScheme || undefined,
                    subdomains: item.subdomains || undefined,
                });
                handle = this.AddImageryLayer(provider, show, alpha, zIndex)
                break
         
            case 'imagery_wms':

                provider = new Cesium.WebMapServiceImageryProvider({
                    url: item.url!,
                    layers: item.layer!,
                    parameters: {
                        service: 'WMS',
                        transparent: true,
                        format: 'image/png',
                        srs: 'EPSG:4326'
                    }

                });
                // 监听错误,抛出自定义异常
                provider.errorEvent.addEventListener(() => {
                    throw new Error('WMS 服务不可用，请检查wms服务地址和图层名称是否正确!');
                });

                handle = this.AddImageryLayer(provider, show, alpha, zIndex)


                break
            case 'imagery_xyz':
                provider = new Cesium.UrlTemplateImageryProvider({
                    url: item.url!,             
                })
              
                handle = this.AddImageryLayer(provider, show, alpha, zIndex)
                break
            /* ---- 地形 ---- */
            case 'terrain':
                this.viewer.terrainProvider = await Cesium.CesiumTerrainProvider.fromUrl(
                    item.url!,
                    {
                        requestWaterMask: item.requestWaterMask ?? false,
                        requestVertexNormals: item.requestVertexNormals ?? false,
                    }
                );
                handle = { __terrain: true }; // 占位，方便 remove 时切回 ellipsoid
                break

            /* ---- 矢量 ---- */
            case 'geojson':
                handle = await Cesium.GeoJsonDataSource.load(item.url!, {
                    clampToGround: true,
                });
                (handle as Cesium.GeoJsonDataSource).show = show;
                this.viewer.dataSources.add(handle)
                //视角
                this.viewer.zoomTo(handle)
                break

            case 'kml':
                handle = await Cesium.KmlDataSource.load(item.url!, {
                    clampToGround: true,
                });
                (handle as Cesium.KmlDataSource).show = show
                this.viewer.dataSources.add(handle)
                this.viewer.zoomTo(handle)

                break

            case 'czml':
                handle = await Cesium.CzmlDataSource.load(item.url!);
                (handle as Cesium.CzmlDataSource).show = show
                this.viewer.dataSources.add(handle)
                this.viewer.zoomTo(handle)
                break

            /* ---- 3DTiles ---- */
            case '3dtiles':
                handle = await Cesium.Cesium3DTileset.fromUrl(item.url!);
                (handle as Cesium.Cesium3DTileset).show = show;
                this.viewer.scene.primitives.add(handle)
                this.viewer.zoomTo(handle, new Cesium.HeadingPitchRange(0.0, -0.3, 0.0))

                // 将3d tiles离地高度抬升500米
                let cartographic = Cesium.Cartographic.fromCartesian(
                    handle.boundingSphere.center
                );

                let surface = Cesium.Cartesian3.fromRadians(
                    cartographic.longitude,
                    cartographic.latitude,
                    0.0
                );

                let offset = Cesium.Cartesian3.fromRadians(
                    cartographic.longitude,
                    cartographic.latitude,
                    500.0
                );

                let translation = Cesium.Cartesian3.subtract(
                    offset,
                    surface,
                    new Cesium.Cartesian3()
                );

                handle.modelMatrix = Cesium.Matrix4.fromTranslation(translation);


                break
            case 'glb':
                let position = Cesium.Cartesian3.fromDegrees(item.lon, item.lat, item.height || 0);
                // 设置模型方向
                let hpRoll = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(item.heading || 45), Cesium.Math.toRadians(item.pitch || 0), Cesium.Math.toRadians(item.roll || 0));
                // 生成一个函数，该函数从以提供的原点为中心的参考帧到提供的椭圆体的固定参考帧计算4x4变换矩阵。
                let fixedFrame = Cesium.Transforms.localFrameToFixedFrameGenerator('north', 'west');
                handle = await Cesium.Model.fromGltfAsync({
                    url: item.url!,
                    modelMatrix: Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, fixedFrame),
                    scale: item.scale || 1,

                });
                handle.show = show;
                this.viewer.scene.primitives.add(handle)
                this.viewer.camera.flyTo({
                    destination: Cesium.Cartesian3.fromDegrees(item.lon, item.lat, 100),
                    duration: 2
                })

                break;

            default:
                throw new Error(`[LayerManager] 未知类型 ${type}`)
        }

        this.layersIdMap.set(item.id, { ...item, handle })
    }

    /**增加影像数据 */
    AddImageryLayer(provider: Cesium.ImageryProvider, show = true, alpha = 1, zIndex = 0) {
        let handle = this.viewer.imageryLayers.addImageryProvider(provider)
        handle.alpha = alpha
        handle.show = show
        this.viewer.imageryLayers.raiseToTop(handle) // 先置顶，再按 zIndex 微调
        if (zIndex)
            this.SetImageryLayerIndex(handle, zIndex)
        return handle
    }

    /**设置影像数据的叠加顺序 */
    SetImageryLayerIndex(layer: Cesium.ImageryLayer, targetIndex: number) {
        const imageryLayers = this.viewer.imageryLayers
        const curIndex = imageryLayers.indexOf(layer)
        if (curIndex === targetIndex) return

        if (targetIndex === 0) {
            imageryLayers.lowerToBottom(layer)          // 直接到底
        } else if (targetIndex === imageryLayers.length - 1) {
            imageryLayers.raiseToTop(layer)            // 直接到顶
        } else {
            // 逐层移动，直到索引匹配
            while (imageryLayers.indexOf(layer) > targetIndex) imageryLayers.lower(layer)
            while (imageryLayers.indexOf(layer) < targetIndex) imageryLayers.raise(layer)
        }
    }

    // 置顶标注图层
    SetAnnotationLayerTop() {
        let annotationHandle = this.layersIdMap.get(LayerIdFlag.TDT_ANNOTATION_WMTS)?.handle
        if (annotationHandle) {
            this.viewer.imageryLayers.raiseToTop(annotationHandle)
        }
    }

    /* 移除图层 */
    Remove(id: string): void {
        const item = this.layersIdMap.get(id)

        if (!item) return;
        const { type, handle } = item;
        switch (type) {
            case 'imagery_wms':
            case 'imagery_wmts':
            case 'imagery_xyz':
                this.viewer.imageryLayers.remove(handle)
                break
            case 'terrain':
                // 回到默认椭球
                this.viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider()
                break
            case 'geojson':
            case 'kml':
            case 'czml':
                this.viewer.dataSources.remove(handle)
                break;
            case '3dtiles':
            case 'glb':
                this.viewer.scene.primitives.remove(handle)
                break;
        }
        this.layersIdMap.delete(id);
    }

    RemoveAllImageLayer() {
        this.viewer.imageryLayers.removeAll()
    }




}